/* #######################################################
 * 
 *                   OWASP CODE CRAWLER
 *                   
 *                         Team
 *                         
 *      Lead Developer:         Alessio Marziali
 *      Contributors:           Sasikumar Ganesan
 *                              Tripurari Rai
 *      
 *                         Links
 *                         
 *  www.owasp.org/index.php/Category:OWASP_Code_Crawler
 *  www.owasp.org
 *  codecrawler.codeplex.com
 *  www.cyphersec.com
 * 
 *  Last update  Jan 2010
 *  
 * #######################################################
 */
using System;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CodeCrawler.UI.Data;
using CodeCrawler.UI.Functionalities.Reporting;
using OWASP.CodeReview.CodeCrawler.Common;
using OWASP.CodeReview.CodeCrawler.Engine.Exceptions;
using OWASP.CodeReview.CodeCrawler.Enums;
using Puzzle.SourceCode;
using Puzzle.Windows.Forms.SyntaxBox;

namespace CodeCrawler.UI.Forms {
    public partial class Presentation : Form {
        /// <summary>
        /// Main Form of OWASP Code Crawler
        /// </summary>
        public Presentation() {
            InitializeComponent();
        }


        public bool IsSourceCodeFileAlreadyLoaded { get; set; }
        public string description { get; set; }

        public ThreatLevel LEVEL { get; set; }
        public DataSet xmlCodeCrawlerDatabase { get; set; } // CodeCrawler Database
        public DataTable threatList { get; set; } // Code Crawler ThreatList
        internal string htmlReportPath { get; set; }
        internal string rtfReportPath { get; set; }
        public string remoteFolderpath { get; set; }


        private void LoadCodeReviewDataBase(CodeCrawlerXMLDatabase DatabaseHelper) {
            DatabaseHelper.CreateThreatTable(CurrentThreatListDataTable);
            xmlCodeCrawlerDatabase = DatabaseHelper.InizializeCodeCrawlerDatabase();
        }


        private void SetCodeViewerValues() {
            CodeViewer.Visible = false;
            CodeViewer.Document.SyntaxFile = Application.StartupPath + "\\C#.syn";
            CodeViewer.Document.Text = string.Empty;
        }

        /// <summary>
        /// Hide / Show HTML Related DropDowns
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiHTMLReportType_CheckedChanged(object sender, EventArgs e) {
            bool isVisible = false;
            if (uiHTMLReportType.Checked) {
                isVisible = true;
            }
            else {
                isVisible = false;
            }

            label1.Visible = isVisible;
            _uiTemplateDropDownList.Visible = isVisible;
        }


        /// <summary>
        /// Launch Generated HTML Report
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LaunchHTMLReport(object sender, EventArgs e) {
            Process.Start(htmlReportPath);
        }


        /// <summary>
        /// Launch RTF Report
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LaunchRTFReport(object sender, EventArgs e) {
            Process.Start(rtfReportPath);
        }


        /// <summary>
        /// Open Single File for Scanning
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OpenFile(object sender, EventArgs e) {
            if ((IsSourceCodeFileAlreadyLoaded) && (FileName.Trim().Length != 0)) {
                CodeViewer.Document.Text = string.Empty;
                CurrentThreatListDataTable.Rows.Clear();
                VulnGrid.DataSource = CurrentThreatListDataTable;
                IsSourceCodeFileAlreadyLoaded = false;
            }

            if (openFileDialog1.ShowDialog() == DialogResult.OK) {
                if (IsSourceCodeFileAlreadyLoaded) IsSourceCodeFileAlreadyLoaded = false;
                CodeViewer.Text = string.Empty;
                FileName = openFileDialog1.FileName;
                CodeViewer.Visible = true;
                CodeViewer.Text = string.Empty;
                IsSourceCodeFileAlreadyLoaded = true;
                ReadSourceFile();
                gocode_Click();
            }
        }


        /// <summary>
        /// Close the Application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CloseApplication(object sender, EventArgs e) {
            Application.Exit();
        }


        private void CodeViewer_RowClick(object sender, RowMouseEventArgs e) {
            int tableIndex;

            if (e.Row.Tag != null) {
                tableIndex = Convert.ToInt32(e.Row.Tag);
                string physicalPath = string.Concat(Application.StartupPath, "/Design/ThreatLevels/",
                                                    VulnGrid.Rows[tableIndex].Cells[2].FormattedValue.ToString(), ".jpg");
                SourceCodeFoundInTextBox.Text = FileName;
                SourceCodeThreatLevelPictureBox.ImageLocation = physicalPath;
                SourceCodeThreatDescriptionTextBox.Text = VulnGrid.Rows[tableIndex].Cells[1].FormattedValue.ToString();
            }
        }


        /// <summary>
        /// Show ViewState Decoder
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void viewstateDecoderToolStripMenuItem_Click(object sender, EventArgs e) {
            var decoderTool = new ViewStateDecoder();
            decoderTool.Show();
        }


        private void openVSNETSolutionToolStripMenuItem_Click(object sender, EventArgs e) {
            //// Show Visual Studio Tab
            //var visualStudioForm = new VisualStudio();
            //visualStudioForm.Show();
        }


        private void aboutCodeCrawlerToolStripMenuItem_Click(object sender, EventArgs e) {
            var formAbout = new About();
            formAbout.Show();
        }


        private void viewStateDecoderToolStripMenuItem1_Click(object sender, EventArgs e) {
            var viewStateDecoderForm = new ViewStateDecoder();
            viewStateDecoderForm.Show();
        }


        private void viewStateDecoderToolStripMenuItem_Click_1(object sender, EventArgs e) {
            var viewStateDecoderForm = new ViewStateDecoder();
            viewStateDecoderForm.Show();
        }

        #region Helper Methods
        /// <summary>
        /// Set default page for OWASP Browser
        /// In this case is Code Review Project
        /// </summary>
        private void NavigateToCodeCrawlerHomePage() {
            var owaspUrl = new Uri("http://www.owasp.org/index.php/Category:OWASP_Code_Review_Project");
            webBrowser1.Navigate(owaspUrl);
        }


        /// <summary>
        /// Specifies which type of files code crawler can open
        /// </summary>
        private void FileDialogSetup() {
            openFileDialog1.Filter = "C# Files (*.cs)|*.cs|VB (*.vb)|*.vb|Java (*.java)|*.java";
        }


        /// <summary>
        /// This is associated with the xx of why code crawler think your code is insecure.
        /// We still haven't fixed a bug with, because, at this time, this code works only on
        /// mouse events (not the keyboard event).
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// TODO: Get the mouse over event to work
        internal void CheckLine(object sender, DataGridViewCellEventArgs e) {
            try {
                v_code.Text = VulnGrid.Rows[e.RowIndex].Cells[1].FormattedValue.ToString();
                uiOwaspGuideLinesRichBox.Text = VulnGrid.Rows[e.RowIndex].Cells[4].FormattedValue.ToString();
                string physicalPath = string.Concat(Application.StartupPath, "/Design/ThreatLevels/",
                                                    VulnGrid.Rows[e.RowIndex].Cells[2].FormattedValue.ToString(), ".jpg");
                uiThreatLevelRappresentation.ImageLocation = physicalPath;

                uiFoundInTextBox.Text = FileName;
            }
            catch (ArgumentOutOfRangeException) {
                // TODO: Fix this
            }
        }


        /// <summary>
        /// Create Threat Grid Columns
        /// </summary>
        internal DataTable CreateVulnGridStructure() {
            var ObjectList = new Objects();
            return ObjectList.CreateThreatListStructure();
        }


        /// <summary>
        /// Read a Source File (as fast as .NET can)
        /// </summary>
        internal void ReadSourceFile() {
            var builder = new StringBuilder();
            using (TextReader reader = File.OpenText(FileName)) {
                string line;
                while ((line = reader.ReadLine()) != null) {
                    builder.AppendLine(line);
                }
            }

            CodeViewer.Document.Text = builder.ToString();
        }


        /// <summary>
        /// This piece of code should be moved into OWASP.CodeReview.CodeCrawler.Engine namespace
        /// </summary>
        internal void DoSingleFileScan() {
            // GridView Properties
            VulnGrid.DataSource = CurrentThreatListDataTable;
            VulnGrid.Width = Width;
            VulnGrid.Columns[2].Width = 0;
            VulnGrid.Columns[2].Visible = false;
            VulnGrid.Columns[3].Visible = false;

            Engine.KeyPointersScan.Core.ScanEngine(ref CurrentThreatListDataTable, xmlCodeCrawlerDatabase, ref VulnGrid,
                                                   FileName);
        }


        /// <summary>
        /// Jump from One line to another
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VulnListJump(object sender, EventArgs e) {
            CheckLine(sender, null);
        }
        #endregion

        #region Menu Click Events
        /// <summary>
        /// Print the source code of the application you are reviewing.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sourceToolStripMenuItem1_Click(object sender, EventArgs e) {
            SourceCodePrintDocument pd;
            pd = new SourceCodePrintDocument(CodeViewer.Document);
            printDialog1.Document = pd;
            if (printDialog1.ShowDialog(this) == DialogResult.OK)
                pd.Print();
        }


        /// <summary>
        /// Start the scanning engine
        /// </summary>
        private void gocode_Click() {
            DoSingleFileScan();

            /// AlterSourceCodeViewer       -> Different Thread
            var sourceCodeViewerColorsthreadStart
                = new ThreadStart(AlterSourceCodeViewerColor);

            // Separate CodeColouring from the UI Thread
            var codeColouring = new Thread(sourceCodeViewerColorsthreadStart);
            codeColouring.Start();

            PopulateExportDropDownList();
        }


        /// <summary>
        /// Populates Template DropDownList 
        /// </summary>
        private void PopulateExportDropDownList() {
            EnsureOutputFolderExists();
            tabControl1.TabPages[4].Focus();

            string combinedPath = string.Concat(Application.StartupPath, "/Results/Templates/");
            var reportsFolder = new DirectoryInfo(combinedPath);
            if (reportsFolder.Exists) {
                string[] templates = Directory.GetFiles(combinedPath);

                foreach (string templateName in templates) {
                    // TODO: Improve Selection
                    // Must show templateName.Remove(0, templateName.IndexOf("OWASP"))
                    _uiTemplateDropDownList.Items.Add(templateName.Replace(combinedPath, ""));
                }
            }
            else {
                throw new UnableToLocateReportsDirectoryException();
            }
        }


        private void AlterSourceCodeViewerColor() {
            int lineNumber;

            try {
                for (int index = 0;
                     index < CurrentThreatListDataTable.Rows.Count;
                     index++) {
                    lineNumber = Convert.ToInt32(CurrentThreatListDataTable.Rows[index][3]);
                    Row r;
                    r = CodeViewer.Document[lineNumber - 1];

                    switch ((ThreatLevel) CurrentThreatListDataTable.Rows[index][2]) {
                        case ThreatLevel.Green:
                            r.BackColor = Color.DarkSeaGreen;
                            r.Tag = index;
                            break;
                        case ThreatLevel.Yellow:
                            r.BackColor = Color.PaleGoldenrod;
                            r.Tag = index;
                            break;
                        case ThreatLevel.Red:
                            r.BackColor = Color.Red;
                            r.Tag = index;
                            break;
                        default:
                            r.BackColor = Color.Red;
                            r.Tag = index;
                            break;
                    }
                }
            }
            catch (InvalidCastException) {
                //TODO: This error should happen only when some one has changed the datatable
                //should log a message into a logger
            }
        }


        private static void EnsureOutputFolderExists() {
            string folderPath = string.Concat(Application.StartupPath, "/Reports");

            var outputDirectory = new DirectoryInfo(folderPath);
            var ioPermission = new FileIOPermission(FileIOPermissionAccess.AllAccess, folderPath);

            try {
                ioPermission.Demand();

                if (!outputDirectory.Exists) {
                    outputDirectory.Create();
                }
            }
            catch (SecurityException) {
                MessageBox.Show(
                    "Current account doesn't have FileIOPermission.AllAccess permission which is required by CodeCrawler in order to create application folders");
            }
        }
        #endregion

        #region Code Crawler Objects
        /// <summary>
        /// This will act as a container for all the threats found into the current file
        /// </summary>
        public DataTable CurrentThreatListDataTable = new DataTable("ThreatList");
        private string FileName = string.Empty;
        /// <summary>
        /// Unique Marker for the selected File (most realated to the reports functionality)
        /// </summary>
        public string selectedDumpFile { get; set; }
        #endregion

        #region Private Methods
        /// <summary>
        /// Code Crawler Starts
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e) {
            var databaseHelper = new CodeCrawlerXMLDatabase();
            LoadCodeReviewDataBase(databaseHelper);

            SetCodeViewerValues();
            FileDialogSetup();
            NavigateToCodeCrawlerHomePage();
        }
        #endregion

        #region Public Methods
        #endregion

        #region Reports TAB
        /// <summary>
        /// This will generate the XML Reports
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateReports(object sender, EventArgs e) {
            // Guess the Templates Folder
            string reportPath = string.Concat(Application.StartupPath, "/Results/Templates/");

            uiHTMLReportButton.Visible = false;
            uiRTFReportButton.Visible = false;
            uiReportOutputGroupBox.Visible = false;

            // HTML CheckBox
            if (uiHTMLReportType.Checked) {
                if (string.IsNullOrEmpty(selectedDumpFile)) {
                    MessageBox.Show("Please select an existing HTML Template", "HTML Template is missing",
                                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else {
                    // Generate HTML Reports
                    htmlReportPath = Reporting.GenerateHTML(selectedDumpFile,
                                                            _uiTemplateDropDownList.SelectedItem.ToString(),
                                                            _uiReportName.Text);

                    uiHTMLReportButton.Visible = true;
                    uiReportOutputGroupBox.Visible = true;
                }
            }

            // RTF CheckBox
            if (uiRTFReportyType.Checked) {
                rtfReportPath = Reporting.GenerateRTF(selectedDumpFile, _uiReportName.Text);
                if (!string.IsNullOrEmpty(rtfReportPath)) {
                    uiRTFReportButton.Visible = true;
                    if (!uiReportOutputGroupBox.Visible) {
                        uiReportOutputGroupBox.Visible = true;
                    }
                }
                else {
                    uiRTFReportButton.Visible = false;
                }
            }

            // Warning Message
            if ((!uiHTMLReportType.Checked) && (!uiRTFReportyType.Checked)) {
                MessageBox.Show("Please select at least one of more Report Format", "Report Format Exception",
                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }


        /// <summary>
        /// Set rtfReportPath and dumpFolderFileLocation with their relative path locations
        /// </summary>
        /// <param name="rtfReportPath"></param>
        /// <param name="dumpFolderFileLocation"></param>
        private void SetRTFReportsLocationPath(out string rtfReportPath) {
            // Guess RTF Repository Folder
            rtfReportPath = string.Concat(Application.StartupPath, "/Results/RTF/");
        }


        /// <summary>
        /// Refresh the Listview and populate it with the dumpFile Lists
        /// TODO: Naming Conventions!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ReloadScanList(object sender, EventArgs e) {
            string reportsDirectory = string.Concat(Application.StartupPath, "/Results/DumpsData/");
            var dumpFolderRepository = new DirectoryInfo(reportsDirectory);

            // If a folder containing dumps exists
            if (dumpFolderRepository.Exists) {
                var dumpFilesRepository = new DataTable();
                dumpFilesRepository.Columns.Add("File", typeof (string));
                dumpFilesRepository.Columns.Add("Keywords", typeof (int));
                dumpFilesRepository.Columns.Add("Date", typeof (string));
                dumpFilesRepository.Columns.Add("Path", typeof (string));

                // Only load files created by OWASP Code Crawler
                foreach (FileInfo singleDumpFile in dumpFolderRepository.GetFiles("*.owasp")) {
                    // File Found Read Content and generate a new ListViewItem filled with informations regarding vulns, date of creation
                    string[] specificSingleDumpFile = Reporting.ReadSingleFileDump(singleDumpFile);
                    DataRow historyRecord = dumpFilesRepository.NewRow();
                    historyRecord[0] = specificSingleDumpFile[0];
                    historyRecord[1] = specificSingleDumpFile[1];
                    historyRecord[2] = specificSingleDumpFile[2];
                    historyRecord[3] = specificSingleDumpFile[3];
                    dumpFilesRepository.Rows.Add(historyRecord);
                }

                _uiGridViewResults.DataSource = dumpFilesRepository;
                _uiGridViewResults.Columns[3].Visible = false;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void selectedDump(object sender, DataGridViewCellEventArgs e) {
            selectedDumpFile = (((DataGridView) sender).SelectedCells)[3].FormattedValue.ToString();
        }
        #endregion
    }
}